package indi.zhifa.recipe.bailan.framework.web.common.filter;

import com.fasterxml.jackson.core.JsonParseException;
import indi.zhifa.recipe.bailan.framework.common.entity.dto.RestResponse;
import indi.zhifa.recipe.bailan.framework.common.entity.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * Description: 处理Spring Validation验证框架对参数的验证机制提供了@Validated（Spring's JSR-303规范，是标准JSR-303的一个变种）
     * @author: bixuejun(bxjgood@163.com)
     * @date:  2021/11/27 18:32
     * @param 
     * @return 
     */
    @ExceptionHandler(value = {ConstraintViolationException.class, MethodArgumentNotValidException.class, BindException.class})
    @ResponseBody
    public RestResponse<Object> argumentValidException(HttpServletRequest req, Exception ex) {
        StringBuilder sb = new StringBuilder("参数验证失败:");
        //Controller上 @Valid + 校验标签(例如@NotBlank()) 在方法形参 中直接校验参数抛出异常
        if(ex instanceof ConstraintViolationException){
            ConstraintViolationException ce = (ConstraintViolationException) ex;
            Set<ConstraintViolation<?>> errors = ce.getConstraintViolations();
            errors.forEach(error->{
                sb.append(error.getMessage()).append(";");
            });
            //@Valid + @RequestBody 校验出错抛出的异常
        }else if(ex instanceof MethodArgumentNotValidException){
            MethodArgumentNotValidException me = (MethodArgumentNotValidException) ex;
            List<ObjectError> errors = me.getBindingResult().getAllErrors();
            errors.forEach(error->{
                sb.append(error.getDefaultMessage()).append(";");
            });
            //@Valid User user校验实体类中字段出错时抛出的异常
        }else if (ex instanceof BindException){
            BindException be = (BindException) ex;
            List<ObjectError> errors = be.getAllErrors();
            errors.forEach(error->{
                sb.append(error.getDefaultMessage()).append(";");
            });
        }
        log.debug("op=global_exception_handler_log_ServiceException", ex);
        return RestResponse.error(sb.toString());
    }
    @ExceptionHandler(JsonParseException.class)
    @ResponseBody
    public RestResponse jsonValidException() {
        return RestResponse.error("Json格式错误!");
    }
    /**
     * Description: 业务主动抛出的异常
     * @author: bixuejun(bxjgood@163.com)
     * @date:  2021/11/27 19:29
     * @param
     * @return
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public RestResponse otherException(ServiceException ex) {
        RestResponse result = null;
        if (null != ex){
            log.debug("op=global_exception_handler_log_ServiceException", ex);
            int code = ex.getCode();
            if(code ==0 || code == 500){
                result = RestResponse.error(ex.getMsg());
            }else{
                result = RestResponse.error(code,ex.getMsg());
            }
        }

        return result;
    }
    /**
     * Description: 系统抛出的未知异常
     * @author: bixuejun(bxjgood@163.com)
     * @date:  2021/11/27 19:26
     * @param
     * @return
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public RestResponse handle(Exception e) {
        log.error("op=global_exception_handler_log_unknowError", e);
        return RestResponse.error("发生未知错误 "+e.toString());
    }
}
